(study) 파이썬 입문 (11주차) 5월9일
클래스 공부 1단계, 2단계
- (1/3) 이미지자료 불러오기 (PIL 이용)
- (2/3) 클래스의 성능 정리
- (3/3) 연습문제
import requests
from PIL import Image
- 예제1
url= 'https://stat.jbnu.ac.kr/sites/stat/images/intro_about_02.jpg'
Image.open(Image.io.BytesIO(requests.get(url).content))
- 우리학과 실습실!
- 예제2
url1 = 'https://github.com/guebin/IP2022/blob/master/_notebooks/2022-05-07-stop1.jpeg?raw=true'
url2 = 'https://github.com/guebin/IP2022/blob/master/_notebooks/2022-05-07-stop2.png?raw=true'
Image.open(Image.io.BytesIO(requests.get(url1).content))
Image.open(Image.io.BytesIO(requests.get(url2).content))
- 클래스를 선언
class STOOOP:
title = '학교폭력!'
url = url1
end = '멈춰~~~~'
def stop(self):
print(self.title)
display(Image.open(Image.io.BytesIO(requests.get(self.url).content)))
print(self.end)
- 규칙1: 메소드(=class안에서 정의된 함수)의 첫번째 인자는 무조건 self
- 규칙2: 메소드에서 class안에 정의된 변수들(title, url, end)을 사용하려면 "self.변수이름"와 같은 형식으로 쓴다.
- 즉 "self.title", "self.url", "self.end" 와 같은 방식으로 써야한다.
- 참고: 규칙2에서 가끔 self의 자리에 "STOOOP.title","STOOOP.url","STOOOP.end" 와 같이 클래스의 이름으로 쓰기도 한다.
- 클래스 사용예시
(예시1) STOOOP 클래스 -> school 인스턴스 만듬
school = STOOOP()
school.stop()
(예시2) STOOOP 클래스 -> kospi 인스턴스 만듬
kospi = STOOOP()
kospi.title = 'KOSPI 하락'
kospi.stop()
- 성능1: 틀만있으면 여러개의 독립적인 컨텐츠를 생성할 수 있다
school = STOOOP()
kospi = STOOOP()
- 함수의 사용법과 비슷하다.
- 클래스이름을 쓰고 콘텐츠를 구체화하는 과정에서 필요한 입력1, 입력2를 ()에 넣는다. 이때는 STOOOP(입력1,입력2)와 같이 생성
- 위의 예시는 따로 입력이 없으므로 비워둔 상태임. 즉 STOOOP()와 같은 식으로 생성.
- 성능2: 생성된 콘텐츠(=인스턴스)에서 .을 찍고 접근할 수 있는 여러 자료들에 접근가능하며 내용도 독립적으로 바꿀 수 있다.
school.title # 출력
kospi.title # 출력
kospi.title = '코스피하락' # 변경
- 성능3: 생성된 콘텐츠(=인스턴스)에서 .을 찍고 쓸 수 있는 자체적인 함수(=method라고 함)를 독립적으로 사용할 수 있다.
school.stop()
kospi.stop()
문제1: 아래의 클래스를 구현하라.
- 클래스내에는 변수 a가 있다. 변수 a의 초기값은 True이다.
- 클래스에는 show()라는 메소드가 있다. show()의 기능은 a의 값을 print하는 기능을 한다.
(풀이)
class Klass1:
a = True
def show(self):
print(self.a)
ex1 = Klass1()
ex1.a
ex1.show()
문제2: 아래의 클래스를 구현하라.
- 클래스내에는 변수 a가 있다. 변수 a의 초기값은 1이다.
- 클래스에는 up()라는 메소드가 있다. up()의 기능은 a의 값을 1증가시키는 기능을 한다.
(풀이)
class Klass2:
a = 1
def up(self):
self.a = self.a + 1
ex2 = Klass2()
ex2.a
ex2.up()
ex2.a
ex2.up()
ex2.up()
ex2.up()
ex2.a
문제3: 아래의 클래스를 구현하라.
- 클래스내에는 변수 a가 있다. 변수 a의 초기값은 0이다.
- 클래스에는 up(),down(),show()라는 메소드가 있다. 각각은 a의 값을 1증가, a의 값을 1감소, a의 값을 print하는 기능을 한다.
(풀이)
class Klass3:
a = 0
def up(self):
self.a = self.a + 1
def down(self):
self.a = self.a - 1
def show(self):
print(self.a)
ex3=Klass3()
ex3.show()
ex3.up()
ex3.show()
ex3.up()
ex3.up()
ex3.show()
ex3.up()
ex3.down()
ex3.show()
ex3.down()
ex3.down()
ex3.show()
문제4: 아래의 클래스를 구현하라.
- 클래스내에는 변수 url이 있음. url의 초기값은 https://github.com/guebin/IP2022/blob/master/_notebooks/2022-05-07-stop1.jpeg?raw=true이다.
- 클래스에는 show()이라는 메소드를 가지는데, 메소드는 아래와 같은 기능을 한다.
- 기능1: url의 그림을 출력
- 기능2: '당신은 이 그림을 $n$번 보았습니다' 출력. 여기에서 $n$은 그림을 본 횟수
(풀이)
class Klass4:
n = 1
url = 'https://github.com/guebin/IP2022/blob/master/_notebooks/2022-05-07-stop1.jpeg?raw=true'
def show(self):
display(Image.open(Image.io.BytesIO(requests.get(self.url).content)))
print("당신은 이 이미지를 {}번 보았습니다".format(self.n))
self.n = self.n+1
a=Klass4()
a.show()
b=Klass4()
b.url = url2
b.show()
- 클래스를 선언하라. ["가위","바위","보"]중 하나를 골라서 내는 메소드를 정의하라.
hint
import numpy as np
np.random.choice(["가위","바위","보"])
- (1/5) __init__
- (2/5) self의 의미
- (3/5) 파이썬의 비밀1
- (4/5) 파이썬의 비밀2
- (5/5) 숙제설명
from PIL import Image
import requests
- STOOOP을 다시 복습
url1 = 'https://github.com/guebin/IP2022/blob/master/_notebooks/2022-05-07-stop1.jpeg?raw=true'
url2 = 'https://github.com/guebin/IP2022/blob/master/_notebooks/2022-05-07-stop2.png?raw=true'
class STOOOP:
title = '학교폭력!'
url = url1
end = '멈춰~~~~'
def stop(self):
print(self.title)
display(Image.open(Image.io.BytesIO(requests.get(self.url).content)))
print(self.end)
s1=STOOOP() # STOOOP이라는 클래스에서 s1이라는 인스턴를 만드는 과정
s1.title,s1.url,s1.end
s1.stop()
- 왜 s1의 default title이 항상 "학교폭력"이어야 하는가? -> __init__의 개발
- 성능4: __init__()함수를 이용하여 "클래스->인스턴스"의 시점에서 수행하는 일련의 동작들을 묶어서 수행할 수 있음
class STOOOP:
#title = '학교폭력!'
url = url1
end = '멈춰~~~~'
def __init__(self,title):
self.title = title
def stop(self):
print(self.title)
display(Image.open(Image.io.BytesIO(requests.get(self.url).content)))
print(self.end)
- 잘못된사용
s1=STOOOP() # 이 시점에서 __init__ 이 수행된다!
- 올바른사용
s1=STOOOP("수강신청매크로") # 이 시점에서 __init__ 이 수행된다!
s1.title,s1.url,s1.end
s1.stop()
- 잘못된사용에서 에러가 발생한 이유?
TypeError: __init__() missing 1 required positional argument: 'title'
- s1 = STOOOP() 이 실행되는 순간
__init__()이 내부적으로 실행된다. - 그런데
__init__()의 첫번째 입력인self는 입력안해도 무방했음. 그런데 두번째 입력은 title은 입력을 해야했음. - 그런데 title을 입력하지 않아서 발생하는 에러
- __init__(self,arg1,arg2,...) 함수에 대하여
- 엄청나게 특별해 보이지만 사실 몇가지 특별한 점을 제외하고는 어떠한 마법도 없는 함수이다.
- 특별한점1: 첫번째 입력으로 반드시 self를 넣어야함. (이건 사실 클래스 내의 메소드 거의 다 그러함)
- 특별한점2: 클래스에서 인스턴스를 만드는 시점에 자동으로 실행된다.
- 특별한점3:
__init__(self,arg1,arg2,...)의 입력중 self 이외의 입력들은 "클래스->인스턴스"의 시점에서 "인스턴스이름 = 클래스이름(arg1,arg2,...)"와 같이 사용한다. (이 예제의 경우 STOOOP(title)와 같이 사용해야함)
- title이 디폴트로 들어가는 상황도 불편했지만, title을 명시적으로 넣지 않으면 에러가 발생하는 것도 불편하다?
class STOOOP:
#title = '학교폭력!'
url = url1
end = '멈춰~~~~'
def __init__(self,title=None):
self.title = title
def stop(self):
print(self.title)
display(Image.open(Image.io.BytesIO(requests.get(self.url).content)))
print(self.end)
s2 = STOOOP()
s3 = STOOOP('KOSPI 하락')
s2.stop()
- 제목이 없으면 없는대로 출력가능
s3.stop()
- 이전 예제를 다시 복습
class Klass4:
n = 1
url = 'https://github.com/guebin/IP2022/blob/master/_notebooks/2022-05-07-stop1.jpeg?raw=true'
def show(self):
display(Image.open(Image.io.BytesIO(requests.get(self.url).content)))
print("당신은 이 이미지를 {}번 보았습니다".format(self.n))
self.n = self.n+1
k4=Klass4()
k4.show()
- 위의 예제는 아래와 같이 구현할 수도 있다.
class Klass4:
n = 1
url = 'https://github.com/guebin/IP2022/blob/master/_notebooks/2022-05-07-stop1.jpeg?raw=true'
def show(self):
display(Image.open(Image.io.BytesIO(requests.get(self.url).content)))
print("당신은 이 이미지를 {}번 보았습니다".format(self.n))
#self.n = self.n+1
k4 = Klass4()
k4.n
k4.show()
k4.n = k4.n + 1
k4.show()
k4.n = k4.n + 1
- 결국에는 k4.n = k4.n + 1의 기능을 구현하여 넣은것이 self.n = self.n + 1 이다.
- 따라서 self는 k4에 대응한다. 즉 self는 인스턴스의 이름에 대응한다. 우리가 하고 싶은 것은 클래스를 선언하는 시점에서 인스턴스가 생성된 이후시점에 대한 어떠한 동작들을 정의하고 싶다. 그런데 클래스를 설계하는 시점에서는 인스턴스의 이름이 정해지지 않았으므로 (아직 인스턴스가 태어나지도 않음) 이러한 동작들을 정의하기 불편하다. 그래서 클래스를 설계하는 시점에서 그 클래스로부터 만들어지는 인스턴스는 그냥 self라는 가칭으로 부른다. (굳이 비유하면 self는 인스턴스의 태명같은 것임)
- 요약: self의 의미는 (후에 만들어질) 인스턴스의 이름이다. (즉 self는 인스턴스의 태명같은것임)
탐구: 인스턴스의 자료형이 뭔지 탐구해보자!
- 아래의 두 클래스를 선언해보자.
class STOOOP:
#title = '학교폭력!'
url = url1
end = '멈춰~~~~'
def __init__(self,title=None):
self.title = title
def stop(self):
print(self.title)
display(Image.open(Image.io.BytesIO(requests.get(self.url).content)))
print(self.end)
class Klass4:
n = 1
url = 'https://github.com/guebin/IP2022/blob/master/_notebooks/2022-05-07-stop1.jpeg?raw=true'
def show(self):
display(Image.open(Image.io.BytesIO(requests.get(self.url).content)))
print("당신은 이 이미지를 {}번 보았습니다".format(self.n))
#self.n = self.n+1
- 인스턴스를 생성해보자.
k4=Klass4()
s1=STOOOP()
- 타입을 알아보자.
k4?
s1?
- ??? 타입은 자료형, 즉 int, float, list 이런것 아니었나??
a=[1,2,3]
a?
- 그런데 지금 k4, s1의 타입은 Klass4, STOOOP 이다.
- 가설1: 사실 파이썬 내부에 Klass4, STOOOP이라는 자료형이 있었다. 그런데 내가 만든 k4, s1이 우연히 그 자료형을 따르는 것! (이건 너무 억지스럽다)
- 가설2: type이 list인것은 사실 list라는 클래스에서 생긴 인스턴스이다 -> 리스트자료형을 찍어낼 수 있는 어떠한 클래스가 파이썬에 내부적으로 존재할 것이다. (이게 맞는것 같다)
깨달음1
- 가설2가 맞다? 그렇다면 아래는 모두 어딘가에서 찍혀진 인스턴스이다.
a=[1,2,3]
a?
a=1,2,3
a?
a=1
a?
a='1'
a?
- 그리고 위의 a=[1,2,3]과 같은 것들은 모두 "클래스->인스턴스"에 해당하는 과정이었음
깨달음2
- 생각해보니까 아래와 같이 list를 선언하는 방식도 있었음
a=list()
a
- 이거 지금 생각하니까 list라는 이름의 클래스에서 a라는 인스턴스를 찍어내는 문법이다?!
- 아래도 가능함
a=list((1,2,3))
a?
- 이것도 지금 보니까 list라는 이름의 클래스에서 a라는 인스턴스를 찍어내는 문법이다. 여기에서 (1,2,3)은
__init__()의 입력이다.
깨달음3
- 그러고보니까 각 자료형마다 특수한 기능들이 있었음
a=[1,2,3]
- a.+tab 을 하면 append, clear 등등이 나온다.
- 이러한 기능은 지금까지 우리가 "list자료형 특수기능들"이라고 부르면서 사용했었다. 그런데 a가 list클래스에서 생성된 인스턴스라는 관점에서 보면 이러한 기능들은 list클래스에서 정의된 메소드라고 볼 수 있다.
깨달음4
- a.f()는 f(a)로 해석가능하다고 하였다. 이 해석에 따르면 메소드의 첫번째 입력은 메소드가 소속된 인스턴스라고 해석할 수 있다.
- 동일한 논리로 아래의 코드는 stop()의 입력에서 s1을 넣는다는 의미이다.
s1.stop()
아래의 조건에 맞는 클래스를 생성하라.
(1) ['가위','바위']와 같은 리스트를 입력으로 받아 인스턴스를 생성한다.
(2) 위의 리스트에서 하나의 값을 뽑는 메소드 f를 가지고 있다.
사용예시
a = Klass(['가위','바위'])
a.f() # 가위가 1/2 바위가 1/2의 확률로 출력
b = Klass(['가위','바위','보'])
b.f() # 가위, 바위, 보가 1/3의 확률로 출력
5월16일에 1시간, 5월18일에 2시간 분량을 업로드하겠습니다. (원래 5월16일 2시간, 5월18일 1시간 분량이었습니다)